package com.momoc.mrpc.register;

import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.momoc.mrpc.config.MRpcConfig;
import com.momoc.mrpc.register.definition.MRpcRegDefinition;
import com.momoc.mrpc.rpc.init.Start;
import com.momoc.mrpc.rpc.serialize.DefaultMRpcSerializeMode;
import com.momoc.mrpc.util.ServerInitUtil;
import java.net.Inet4Address;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author momoc
 * @version 1.0
 * @className NacosRegisterImpl
 * @description
 * @date 2022/7/25 6:57 下午
 */
@Slf4j
@Component
public class NacosRegisterImpl implements RegisterCenter {


    @Value("${spring.application.name:mrpc}")
    String applicationName;


    @Autowired
    DefaultMRpcSerializeMode defaultMRpcSerializeMode;

    @Resource
    Start start;

    @Autowired
    MRpcConfig mRpcConfig;
    /**
     * 注册远程调用的服务列表
     */
    public static String mrpcServiceName = "mRpc";

    ScheduledExecutorService service = Executors.newScheduledThreadPool(1);

    @Autowired
    NamingService namingService;

    @Autowired
    ConfigService configService;


    @Override
    public void register(Map<String, MRpcRegDefinition> rpcNameServiceMap) throws NacosException {
        String hostAddress = Inet4Address.getLoopbackAddress().getHostAddress();
        String serviceName = applicationName;
        Instance instance = new Instance();
        instance.setIp(hostAddress);
        instance.setPort(Integer.parseInt(Start.serverInitStatus.getServerPort()));
        instance.setHealthy(true);
        instance.setServiceName(applicationName + Inet4Address.getLoopbackAddress().getHostAddress());
        instance.setEphemeral(true);
        Map<String, String> metadata = new HashMap<>();
        try {
            Start.serverInitStatus.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //唤醒注册服务
        metadata.put("server.name", serviceName);
        instance.setMetadata(metadata);
        namingService.registerInstance(mrpcServiceName, instance);
        //订阅服务
        namingService.subscribe(mrpcServiceName, event -> {
            NamingEvent namingEvent = (NamingEvent) event;
            List<Instance> instancesList = namingEvent.getInstances();
            RegisterContext.setOnlineServer(instancesList);
        });


        for (Map.Entry<String, MRpcRegDefinition> mRpcRegDefinitionEntry : rpcNameServiceMap.entrySet()) {
            String dataId = mRpcRegDefinitionEntry.getKey();
            MRpcRegDefinition value = mRpcRegDefinitionEntry.getValue();
            String config = configService.getConfig(dataId, "mapping", 5000);
            if (config == null) {
                config = serviceName;
            } else {
                if (!config.contains(serviceName)) {
                    config += "\n" + serviceName;
                }
            }
            configService.publishConfig(dataId, "mapping", config);
            RegisterContext.getClassName2String().put(dataId, config);
            RegisterContext.getClassName2Service().put(dataId, Arrays.asList(config.split("\n")));
            //订阅配置信息
            service.scheduleAtFixedRate(() -> {
                try {
                    String mapping = configService.getConfig(dataId, "mapping", 5000);
                    Map<String, String> className2String = RegisterContext.getClassName2String();
                    Map<String, List<String>> className2Service = RegisterContext.getClassName2Service();
                    if (className2String.get(dataId).equals(mapping)) {
                        return;
                    }
                    log.info("服务发现变化：{}->{}", dataId, mapping);
                    className2String.put(dataId, mapping);
                    className2Service.put(dataId, Arrays.asList(mapping.split("\n")));
                } catch (NacosException e) {
                    e.printStackTrace();
                }
            }, 0, 5, TimeUnit.SECONDS);
        }

        log.info("服务注册完成！");
    }

    @Override
    public String getRegisterName() {
        return "nacos";
    }
}
